home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 …ember: Reference Library / Dev.CD Dec 94.toast / What's New? / Sample Code / Snippets Update / Movie SetTrackGWorld ƒ / TransferStuff.c < prev   
Encoding:
Text File  |  1994-10-21  |  11.4 KB  |  382 lines  |  [TEXT/KAHL]

  1. // Sample code to check out the QuickTime 1.6 transfer proc stuff.  Essentially we have a movie that is 
  2. // drawn into a gworld that we create, and our transfer proc should get called after each frame is drawn.
  3. //
  4. // This program draws a fram marker on each new frame as the movie is displayed - these markers are
  5. // essentially just numbers, and come from a marker pict.  each marker is 32x32, the pict contains
  6. // 10 of them and the appropriate marker is copied from the pict to the movie frame.
  7. //
  8. // This is not intended as a complete example.  For a start the markers are clipped to a circular shape
  9. // and that is slow, also we use copybits without trying to optimise the frawing.  As a consequence you
  10. // would only expect to see around 8 frames a second for this technique as implemented.  With optimisation
  11. // the Quicktime team have seen rates of up to 30 FPS.  To optimise the copybits calls, read the technote
  12. // “of time and space and copybits”, and use rectangular clipping regions.  This snippet illustrates how to 
  13. // draw over a frame of a quicktime movie as the movie is playing.
  14. //
  15. // We use set SetTrackGWorld:
  16. //
  17. //        SetTrackGWorld
  18. //        
  19. //        SetTrackGWorld lets you force a track to draw into a particular GWorld. This 
  20. //        GWorld may be different from that of the entire movie. After the track has drawn, 
  21. //        it calls your transfer procedure to copy the track to the actual movie GWorld. 
  22. //        When your transfer procedure is set, the current GWorld is set to the correct 
  23. //        destination. You can also install a transfer procedure and set the GWorld to nil. 
  24. //        This results in your transfer procedure being called only as a notification that 
  25. //        the track has drawn—no transfer needs to take place.
  26. //        
  27. //        pascal void SetTrackGWorld( Track theTrack, 
  28. //                                    CGrafPtr port, 
  29. //                                    GDHandle gdh, 
  30. //                                    TrackTransferProc proc, 
  31. //                                    long refCon) ;
  32. //                                    
  33. //        theTrack    The track to set the proc to.
  34. //        port        The port for the track to draw to, or nil to use the movie’s GWorld.
  35. //        gdh            GDevice associated with the port, or nil.
  36. //        proc        Returns pointer to your transfer procedure, or nil to remove it.
  37. //        refCon         Value to pass to your transfer procedure.
  38. //        
  39. //        typedef pascal OSErr (*TrackTransferProc)(Track t, long refCon);
  40. //
  41. // Remember to use the UPP creation procedure - NewTrackTransferProc - when you install the transfer proc,
  42. // this makes life better on powerpc.  If you forget, then you compile native, then the app will crash when
  43. // the callback is made.
  44. //        
  45. // Nick Thompson, 10/21/94, AppleLink NICKT
  46. //
  47. //    Copyright:    © 1992-4 by Apple Computer, Inc., all rights reserved.
  48.  
  49. #include <movies.h>
  50.  
  51.  
  52. // function prototypes
  53. Track    GetFirstTrackOfType( Movie    aMovie, OSType    trackType ) ;
  54. pascal     OSErr myTrackTransferProc(Track t, long refCon) ;
  55. GWorldPtr    SetTransferProcsForMovie( Movie aMovie ) ;
  56.  
  57. OSErr    LoadMarkers( GWorldPtr    theGWorld ) ;
  58. void    DrawMarker( GWorldPtr theGWorld, Rect *destRect, short index )  ;
  59.  
  60. //---------------------------------------------------------------------
  61. // define a structure to hold all the information we need in the transfer
  62. // proc.
  63.  
  64. typedef struct {
  65.     GWorldPtr    movieGWorld ;
  66.     GWorldPtr    trackGWorld ;
  67.     GWorldPtr    markerGWorld ;            // this holds our markers
  68.     Rect        movieRect ;
  69. } TransferData, *TransferDataPtr, **TransferDataHandle ;
  70.     
  71.  
  72. enum { kMarkerID = 1000 } ;
  73. static const     short    markerWidth = 32 ;
  74. static const     short    markerHeight = 32 ;
  75. static const     Rect kMarkerBounds = { 0, 0, 32, 320 } ;
  76.  
  77. static            RgnHandle pMaskRgn    = nil ;            // the mask region for the frame markers
  78.     
  79. //---------------------------------------------------------------------
  80. //
  81. OSErr LoadMask(void)
  82. {
  83.     PicHandle        thePicture ;
  84.     GWorldPtr        savedGWorld ;
  85.     GWorldPtr        theGWorld ;
  86.     GDHandle         savedDevice ;
  87.     Rect            theFrame = {0,0,32,32} ;
  88.     PixMapHandle    offPixMap ;
  89.     OSErr            theErr ;
  90.  
  91.     
  92.     pMaskRgn = NewRgn() ;
  93.     
  94.     // save our environment
  95.     GetGWorld( &savedGWorld, &savedDevice) ;
  96.  
  97.     // create a small GWorld
  98.     theErr = NewGWorld( &theGWorld, 1, &theFrame, nil, nil, 0L ) ;
  99.     
  100.     // draw into the port we are passed
  101.     SetGWorld( theGWorld, nil ) ;
  102.     
  103.     // get the marker picture
  104.     thePicture = GetPicture( kMarkerID + 1) ;
  105.     
  106.     // there ain't no sanity clause
  107.     if( thePicture == nil ) 
  108.         return ResError() ;
  109.     
  110.     // image the picture
  111.     DrawPicture( thePicture, &theFrame) ;
  112.     
  113.     // free up the space used temproarily by the picture
  114.     ReleaseResource((Handle)thePicture) ;
  115.     
  116.     // set up the mask region
  117.     offPixMap = GetGWorldPixMap( theGWorld ) ;
  118.     LockPixels(offPixMap) ;
  119.     theErr = BitMapToRegion( pMaskRgn, (BitMap *)*offPixMap ) ;
  120.     UnlockPixels(offPixMap) ;
  121.     OffsetRgn( pMaskRgn, 16, 16 ) ;
  122.     
  123.     // restore the drawing environment
  124.     SetGWorld( savedGWorld, savedDevice) ;
  125.     DisposeGWorld( theGWorld ) ;
  126.     return QDError() ;
  127.     
  128. }
  129. //---------------------------------------------------------------------
  130. //
  131.  
  132. OSErr    LoadMarkers( GWorldPtr    theGWorld )
  133. {
  134.     PicHandle    thePicture ;
  135.     GWorldPtr    savedGWorld ;
  136.     GDHandle     savedDevice ;
  137.     Rect        theFrame ;
  138.     
  139.     // save our environment
  140.     GetGWorld( &savedGWorld, &savedDevice) ;
  141.     
  142.     // draw into the port we are passed
  143.     SetGWorld( theGWorld, nil ) ;
  144.     
  145.     // get the marker picture
  146.     thePicture = GetPicture( kMarkerID ) ;
  147.     
  148.     // there ain't no sanity clause
  149.     if( thePicture == nil ) 
  150.         return ResError() ;
  151.     
  152.     // get the picture frame
  153.     theFrame = (**thePicture).picFrame ;
  154.     
  155.     // image the picture
  156.     DrawPicture( thePicture, &theFrame) ;
  157.     
  158.     // free up the space used temproarily by the picture
  159.     ReleaseResource((Handle)thePicture) ;
  160.     
  161.     // restore the drawing environment
  162.     SetGWorld( savedGWorld, savedDevice) ;
  163.     
  164.     return QDError() ;
  165. }
  166.  
  167. //---------------------------------------------------------------------
  168. // Draw the n'th marker - assumes port is set up
  169.  
  170. void    DrawMarker( GWorldPtr theGWorld, Rect *destRect, short index ) 
  171. {
  172.     short            offset = 0 ;
  173.     Rect            srcRect = {0, 0, 32, 32} ;
  174.     PixMapHandle    offPixMap = nil ;
  175.     GrafPtr            theCurrentPort ;
  176.     
  177.     // we need this for the copyBits call
  178.     GetPort( &theCurrentPort ) ;
  179.     
  180.     offset = index *  markerWidth ;
  181.     srcRect.left += offset ;
  182.     srcRect.right += offset ;
  183.     
  184.     offPixMap = GetGWorldPixMap( theGWorld ) ;
  185.     if( offPixMap ) {
  186.         (void) LockPixels( offPixMap ) ;
  187.         
  188.         // copy from the gWorld Image to the window's port
  189.         CopyBits( (BitMap *)*offPixMap,
  190.                   &theCurrentPort->portBits,
  191.                   &srcRect,
  192.                   destRect,
  193.                   srcCopy,
  194.                   nil ) ;
  195.         
  196.         // unlock the pixmap
  197.         (void) UnlockPixels( offPixMap ) ;
  198.     }
  199. }
  200.  
  201. //---------------------------------------------------------------------
  202.  
  203. // locate the first track in a movie with the supplied type
  204. Track    GetFirstTrackOfType( Movie    aMovie, OSType    trackType )
  205. {
  206.     Track     theTrack  = nil ; 
  207.     OSType     mediaType;
  208.     short    trackCount ;
  209.     short    index ;
  210.     
  211.     trackCount = GetMovieTrackCount(aMovie);
  212.     for ( index=1 ; index <= trackCount ; index++) {
  213.         Track t = GetMovieIndTrack(aMovie, index);
  214.  
  215.         GetMediaHandlerDescription(GetTrackMedia(t), &mediaType, nil, nil);
  216.         if (mediaType == trackType) {
  217.             theTrack = t;
  218.             break;
  219.         }
  220.     }
  221.  
  222.     return theTrack ;
  223.  
  224. }
  225.  
  226. //---------------------------------------------------------------------
  227.  
  228. pascal OSErr myTrackTransferProc(Track t, long refCon)
  229. {
  230.  
  231.     TransferDataHandle        myTDH = (TransferDataHandle)refCon ;
  232.     GrafPtr                    theNewWorld ;
  233.     GrafPtr                    movieGWorld ;
  234.     GWorldPtr                markerGWorld ;
  235.     PixMapHandle            offPixMap ;
  236.     Rect                    movieBox ;
  237.     static    short            index = 0 ;
  238.     CGrafPtr                savedWorld ;
  239.     GDHandle                savedDevice ;
  240.     Str255                    theString ;
  241.     
  242.     Rect                    dstRect = { 16, 16, 48, 48 } ;
  243.     
  244.  
  245.     movieGWorld = (GrafPtr)((**myTDH).movieGWorld) ;
  246.     theNewWorld = (GrafPtr)((**myTDH).trackGWorld) ;
  247.     markerGWorld = (**myTDH).markerGWorld ;
  248.     movieBox =     (**myTDH).movieRect ;
  249.     
  250.     offPixMap = GetGWorldPixMap( (GWorldPtr)theNewWorld ) ;
  251.     (void) LockPixels( offPixMap ) ;
  252.     
  253.     GetGWorld( &savedWorld, &savedDevice );
  254.     SetGWorld( (CGrafPtr)theNewWorld, nil ) ;
  255.     
  256.     SetClip( pMaskRgn ) ;
  257. //    ClipRect( &dstRect ) ;            // ensure we have the whole area to draw in
  258.     if(++index > 9) index = 0 ;        // roll the index around
  259.     
  260.     // draw the next marker over the frame
  261.     DrawMarker( markerGWorld, &dstRect, index )  ;
  262.     
  263. //    MoveTo ( 15, 15 );
  264. //    NumToString ( index++, theString );
  265. //    DrawString ( theString );
  266.     
  267.     // copy the image from the offscreen port
  268.     // into the movies port
  269.     
  270.     SetGWorld( savedWorld, savedDevice ) ;
  271.     
  272.     CopyBits(     &theNewWorld->portBits,
  273.                 &movieGWorld->portBits,
  274.                 &theNewWorld->portRect,
  275.                 &movieBox,
  276.                 srcCopy,
  277.                 nil ) ;
  278.  
  279.     (void) UnlockPixels( offPixMap ) ;
  280. }
  281.  
  282. //---------------------------------------------------------------------
  283.  
  284. Media GetFirstVideoMedia(Movie coolMovie, long *trackIndex)
  285. {
  286.   Track    coolTrack = nil;
  287.   Media    coolMedia = nil;
  288.   long    numTracks;
  289.   OSType  mediaType;
  290.   numTracks = GetMovieTrackCount(coolMovie);
  291.   for (*trackIndex=1; *trackIndex<=numTracks; (*trackIndex)++) {
  292.     coolTrack = GetMovieIndTrack(coolMovie, *trackIndex);
  293.     if (coolTrack) coolMedia = GetTrackMedia(coolTrack);
  294.     if (coolMedia) GetMediaHandlerDescription(coolMedia,
  295.       &mediaType, nil, nil);
  296.     if (mediaType = VideoMediaType) return coolMedia;
  297.   }
  298.   *trackIndex = 0;  // trackIndex can't be 0
  299.   return nil;      // went through all tracks and no video
  300. }
  301.  
  302.  
  303.  
  304. //---------------------------------------------------------------------
  305.  
  306. short GetFirstVideoTrackPixelDepth(Movie coolMovie)
  307. {
  308.   SampleDescriptionHandle imageDescH =
  309.     (SampleDescriptionHandle)NewHandle(sizeof(Handle));
  310.   long    trackIndex = 0;
  311.   Media    coolMedia = nil;
  312.   coolMedia = GetFirstVideoMedia(coolMovie, &trackIndex);
  313.   if (!trackIndex || !coolMedia) return -1;  // we need both
  314.   GetMediaSampleDescription(coolMedia, trackIndex, imageDescH);
  315.   return (*(ImageDescriptionHandle)imageDescH)->depth;
  316. }
  317.  
  318.  
  319. //---------------------------------------------------------------------
  320.  
  321. GWorldPtr SetTransferProcsForMovie( Movie aMovie )
  322. {
  323.  
  324.     Rect                    trackDimensions = { 0, 0, 0, 0 };
  325.     GWorldPtr                theNewWorld ;
  326.     GWorldPtr                movieGWorld ;
  327.     GWorldPtr                markerGWorld ;
  328.     GDHandle                theNewWorldDevice = nil;
  329.     
  330.     Rect                    markerBounds = kMarkerBounds ;
  331.     
  332.     Fixed                    height ;
  333.     Fixed                    width ;
  334.     
  335.     OSErr                    theErr ;
  336.     Rect                    movieBox ;
  337.     
  338.     // current environment
  339.     CGrafPtr                savedPort ;
  340.     GDHandle                savedDevice ;
  341.     
  342.     TransferDataHandle        myTDH = (TransferDataHandle)NewHandle( sizeof( TransferData )) ;
  343.     Track                    aTrack = GetFirstTrackOfType( aMovie, VideoMediaType ) ;
  344.     short                    trackDepth = GetFirstVideoTrackPixelDepth( aMovie ) ;
  345.     
  346.     if( myTDH == nil || aTrack == nil || trackDepth < 0)
  347.         return ;
  348.         
  349.     GetTrackDimensions( aTrack, &width, &height ) ;
  350.     
  351.     trackDimensions.right = Fix2Long( width );
  352.     trackDimensions.bottom = Fix2Long( height );
  353.     
  354.     // create the marker gWorld - make this the same
  355.     // depth as the track to improve copybits speed
  356.     theErr = NewGWorld( &markerGWorld, trackDepth, &markerBounds, nil, nil, 0L ) ;
  357.     CheckError( theErr, "\pCall to NewGWorld failed" );
  358.  
  359.     // image the marker picts
  360.     LoadMask() ;                    // this loads our clipping mask - clipping to a mask will give us a performance hit
  361.  
  362.     CheckError( LoadMarkers( markerGWorld ), "\pFailed to load the marker PICT") ;    // load the pict containing our 10 numbered
  363.                                                                                     // circular markers, these are drawn over the frame
  364.  
  365.     (**myTDH).markerGWorld = markerGWorld ;
  366.     
  367.     // create the movie gWorld
  368.     theErr = NewGWorld( &theNewWorld, trackDepth, &trackDimensions, nil, theNewWorldDevice, 0L ) ;
  369.     CheckError( theErr, "\pCall to NewGWorld failed" );
  370.  
  371.     GetMovieGWorld( aMovie, &movieGWorld, nil ) ;
  372.         
  373.     (**myTDH).movieGWorld = movieGWorld ;
  374.     (**myTDH).trackGWorld = theNewWorld ;
  375.     
  376.     GetMovieBox( aMovie, &movieBox ) ;
  377.     (**myTDH).movieRect = movieBox ;
  378.     
  379.     SetTrackGWorld( aTrack, (CGrafPtr)theNewWorld, nil, NewTrackTransferProc( myTrackTransferProc ),  (long)myTDH ) ;
  380.  
  381. }
  382.